package org.spring;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author su
 */
public class SuApplicationContext {

    private Class configClass;
    /**
     * 存放单例对象实例的map
     */
    private ConcurrentHashMap<String, Object> singletonMap =new ConcurrentHashMap<>();
    /**
     * bean的定义map
     */
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap =new ConcurrentHashMap<>();

    private static final String SINGLETON="singleton";

    public SuApplicationContext(Class configClass) throws ClassNotFoundException {
        this.configClass = configClass;
        scan(configClass);
        // 单例bean 在容器启动的时候就要 创建好放入单例map中
        for (Map.Entry<String,BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName=entry.getKey();
            BeanDefinition beanDefinition=entry.getValue();
            if(beanDefinition.getScope().equals(SINGLETON)){
                //创建bean
                Object bean = createBean(beanDefinition);
                //将创建的bean放入单例map中
                singletonMap.put(beanName,bean);

            }
        }
    }

    /**
     * 扫描
     * @param configClass
     * @throws ClassNotFoundException
     */
    private void scan(Class configClass) throws ClassNotFoundException {
        //解析配置类
        //componentsacn  得到路径  扫描
        ComponentScan declaredAnnotations = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
        //扫描路劲   com.su.service
        String path = declaredAnnotations.value();
        //扫描   怎么根据包名得到所有的类
        //利用类加载器  三种类加载器
        // bootstrap  jre/lib
        // ext  jre/ext/lib
        // app      classpath
        path = path.replace(".", "/");
        ClassLoader classLoader = SuApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(path);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                String absolutePath = f.getAbsolutePath();
                if(absolutePath.endsWith(".class")){
                    String com = absolutePath.substring(absolutePath.indexOf("org"), absolutePath.indexOf(".class"));
                    com = com.replace("\\", ".");
                    Class<?> aClass = classLoader.loadClass(com);
                    //表示是一个bean
                    if (aClass.isAnnotationPresent(Component.class)) {
                        // 判断bean的作用域  单例  原型
                        // 每次getBean 都需要解析类  为了解决这个问题
                        //引入 BeanDefinition
                        Component declaredAnnotation = aClass.getDeclaredAnnotation(Component.class);
                        String beanName=declaredAnnotation.value();
                        //通过  BeanDefinition   和beanName获取scope
                        BeanDefinition beanDefinition=new BeanDefinition();
                        beanDefinition.setClazz(aClass);
                        if(aClass.isAnnotationPresent(Scope.class)){
                            Scope scope = aClass.getDeclaredAnnotation(Scope.class);
                            beanDefinition.setScope(scope.value());
                        }else{
                            beanDefinition.setScope(SINGLETON);
                        }
                        beanDefinitionMap.put(beanName,beanDefinition);
                    }
                }
            }
        }
    }

    /**
     * 获取bean
     * @param name
     * @return
     * @throws Exception
     */
    public Object getBean(String name) throws Exception {
        if(beanDefinitionMap.containsKey(name)){
            BeanDefinition beanDefinition =  beanDefinitionMap.get(name);
            //单例
            if(beanDefinition.getScope().equals(SINGLETON)){
                //从单例map中获取对象
                Object bean = singletonMap.get(name);
                return bean;

            }else{
                //原型  创建bean对象
                Object bean = createBean(beanDefinition);
                return bean;
            }
        }else{
            throw new Exception("不存在这个实例");
        }
    }

    /**
     * 创建bean
     * @param beanDefinition
     * @return
     */
    public Object createBean(BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getClazz();
        try {
            Object instance = clazz.getDeclaredConstructor().newInstance();
            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return null;

    }
}
